/***************************************************************
*  Copyright (c) 2007 by GroupMe! Team (www.groupme.net)
*  All rights reserved.
*
*  This file is part of the GroupMe! Project. Source code of 
*  this project is closed and redistribution of this code is
*  prohibited. 
*  
*  Contact: http://www.groupme.net
*
*  This copyright notice MUST APPEAR in all copies of the file!
***************************************************************/
package net.groupme.search.strategy;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import net.groupme.model.Group;
import net.groupme.model.Resource;
import net.groupme.model.Tag;
import net.groupme.search.strategy.model.WeightedGroup;
import net.groupme.search.strategy.model.WeightedResource;

/**
 * created on Jul 4, 2007
 * 
 * This implements the interface {@link ScoringStrategy} by concentrating
 * on the {@link Group} context of a given resource. 
 * 
 * @author Fabian Abel, <a href="mailto:abel@l3s.de">abel@l3s.de</a>
 * @author last edited by: $Author: fabian $
 * 
 * @version $Revision: 1.3 $ $Date: 2007-07-04 13:36:59 $
 */
public class ScoringStrategyGroupContext implements ScoringStrategy {
	
	/** emphasis of a direct tag */
	private double resourceScoringWeight = 2.0;
	
	/** emphasis of a tag which occurs in the context of the resource */
	private double contextScoringWeight = 1.0;
	
	/**
	 * Creates a new ScoringStrategyGroupContext instance.
	 * @param resourceScoringWeight  emphasis of a direct tag
	 * @param contextScoringWeight emphasis of a tag which occurs in the context of the resource 
	 */
	public ScoringStrategyGroupContext(double resourceScoringWeight, double contextScoringWeight){
		this.resourceScoringWeight = resourceScoringWeight;
		this.contextScoringWeight = contextScoringWeight;
	}

	/**
	 * Returns the scoring value of the resource according to its context (= group, user,..).
	 * Thus: How related is the context of the given resource to the given tag?
	 * In detail:
	 * <pre>
	 *          #Groups, that contain the given resource and are tagged with the given tag
	 *  score = ---------------------------------------------------------------------------
	 *                            #Groups, that contain the given resource
	 * </pre>
	 * 
	 * @param resource the resource for which the scoring value should be computed
	 * @param tag the tag which is the basement for the score
	 * @return the score which should be between 0..1
	 */
	public double computeResourceContextScore(Resource resource, Tag tag) {
		Collection<Group> groupsOfResource = resource.getGroups();
		if(groupsOfResource == null || groupsOfResource.size() == 0){
			return 0.0;
		}
		Integer allGroups = groupsOfResource.size();
		Integer numberOfGroupsThatHaveTheTag = 0;
		for(Group group: groupsOfResource){
			if(group.getTags().contains(tag)){
				numberOfGroupsThatHaveTheTag++;
			}
		}
		return numberOfGroupsThatHaveTheTag.doubleValue() / allGroups.doubleValue();
	}

	/* (non-Javadoc)
	 * @see net.groupme.search.strategy.ScoringStrategy#computeOverallContextScore(java.util.Map, java.util.Map)
	 */
	public List<WeightedResource> computeOverallContextScore(Map<WeightedGroup, List<WeightedResource>> groupResourceMapping) {
		List<WeightedResource> contextScoring = new ArrayList<WeightedResource>();
		for(WeightedGroup group: groupResourceMapping.keySet()){
			for(WeightedResource weightedResource: groupResourceMapping.get(group)){
				if(contextScoring.contains(weightedResource.resource)){
					int pos = contextScoring.indexOf(weightedResource.resource);
					//Question: how to combine two values?
					//Here: Just make a sum:
					contextScoring.get(pos).weight += weightedResource.weight;
				}else{
					contextScoring.add(weightedResource);
				}
			}
		}
		return contextScoring;
	}

	/* (non-Javadoc)
	 * @see net.groupme.search.strategy.ScoringStrategy#combineScorings(java.util.Map, java.util.Map)
	 */
	public List<WeightedResource> combineScorings(List<WeightedResource> directResourceScoring, List<WeightedResource> contextScoring) {
		List<WeightedResource> scoring = directResourceScoring;
		for(WeightedResource resourceWeightedAccordingToContext: contextScoring){
			double resourcePart = 0.0;
			//gewichte den Context-part:
			double contextPart = contextScoringWeight * resourceWeightedAccordingToContext.weight;
			
			if(scoring.contains(resourceWeightedAccordingToContext)){
				int pos = scoring.indexOf(resourceWeightedAccordingToContext);
				
				//gewichte den Resource-part:
				resourcePart = resourceScoringWeight * scoring.get(pos).weight;
				
				scoring.get(pos).weight = resourcePart + contextPart;
			}else{
				resourceWeightedAccordingToContext.weight = contextPart;
				scoring.add(resourceWeightedAccordingToContext);
			}
		}
		return scoring;
	}

}
